let soc={},cacheDataObj={},startTime;
importScripts("./pako.min.js");

//解压缩
async function unzip(data){
	let datas = await (new Response(data)).arrayBuffer(),str=[],len=data.length;	
	datas = pako.inflate(new Uint8Array(data));//unzip
	for(let i=0;i<len;i++){
		str[i]=String.fromCharCode(datas[i]);
	}	
	return str;
}

//订阅
function subscribe(msg,resMsg){
	startTime=Date.now();//订阅开始时间
	soc[msg.socketName].send(msg.content);
	resMsg.data=true;
	postMessage(resMsg);
}
//取消订阅
function unsubscribe(msg,resMsg){
	soc[msg.socketName].send(msg.content);
	resMsg.data=true;
	postMessage(resMsg);
}
//主动关闭
function close(msg,resMsg){
	soc[msg.socketName].initiative=true;
	soc[msg.socketName].close();
	//delete soc[msg.socketName];
	resMsg.data=true;
	postMessage(resMsg);
}
/* //zip
function zip(msg,resMsg){
	soc[socketName].zip=msg.content;
	resMsg.data=true;
	postMessage(resMsg);
} */
//连接状态
function connectState(msg,resMsg){
	resMsg.data=soc[msg.socketName]?.connectState
	postMessage(resMsg);
}
//取精简数据
function extract(msg,resMsg){
	resMsg.data=cacheDataObj[msg.socketName].cache[msg.channel].extract(msg.start,msg.end,msg.resLen);
	postMessage(resMsg);
}

onmessage = ev => {
	let msg=ev.data;
	let resMsg={
		id:msg.id,
		socketName:msg.socketName,
		data:null,
		type:msg.type
	}
	if(msg.type=="open" || (soc[msg.socketName] && self[msg.type])){
		self[msg.type](msg,resMsg);
	}else{
		postMessage(resMsg);
	}
}

//初始化websocket及数据缓存 
function open(msg,resMsg){
	//console.log('msg',msg);
	//创建websocket
	if(!msg.socketName || !msg.ws){
		console.log(`【${msg.socketName}】因参数不完整，无法建立连接`);
		return;
	}
	if(soc[msg.socketName]){
		console.log(`标识为【${msg.socketName}】websocket对象已经存在，无法建立连接`);
		return;
	}
	cacheDataObj[msg.socketName]=createCacheData(msg.fs,msg.cacheTimeLen,msg.channelNum,msg.isMultiData);
	soc[msg.socketName]=createWebsocket(msg);
}

/**
 * 在worker中建立websocket,连接对象缓存到soc对象中
 * @param {Object} data{
		socketName 缓存名,用于标识websocket对象
 * 		ws websocket连接地址
 *		zip 数据是否需要zip解压
 * }
 */
function createWebsocket(opts){
	let socket=new WebSocket(opts.ws);
	let socCache=cacheDataObj[opts.socketName].cache;
	socket.onopen=ev=>{
		socket.connectState=true;
		startTime=Date.now();
		console.log(`【${opts.socketName}】连接成功`);
	}
	socket.onmessage=ev=>{
		let data=ev.data;
		if(socket.zip){
			data=unzip(data);
		}
		try{
			data=JSON.parse(ev.data);
		}catch(e){
			//
		}
		let xAxis=new Array(data.length).fill(Date.now()-startTime);
		socCache[1].insert(data,xAxis);
		socCache[2].insert(data,xAxis);
		socCache[3].insert(data,xAxis);
		socCache[4].insert(data,xAxis);
		socCache[5].insert(data,xAxis);
		socCache[6].insert(data,xAxis);
		socCache[7].insert(data,xAxis);
		socCache[8].insert(data,xAxis);
		data=null;
		ev=null;
	}
	socket.onerror=ev=>{
		console.log(`【${opts.socketName}】连接错误`,ev);
	}
	socket.onclose=ev=>{
		//非主动关闭自动重连
		socket.connectState=false;
		if(!socket.initiative){
			console.log(`【${opts.socketName}】连接关闭,5s后重新连接`,ev);
			setTimeout(()=>open(opts),5000);
		}else{
			console.log(`【${opts.socketName}】连接关闭`);
		}
		delete soc[opts.socketName];
	}
	socket.zip=opts.zip;
	return socket;
}

/**
 * 缓存数据
 *@param {Number} cacheTimeLen 缓存时长 默认为1s
 *@param {Number} channelNum 缓存通道数 默认为4 缓存数据用通道序号标识 
 *@param {boolean} isMultiData 通道数据是否为多曲线 默认为false 缓存数据用通道序号标识 
 *  若为boolean，所有通道都是一组数据或多组数据
 *	若为对象，可分别指定不通道的数据形式 如{"1":true,"2":true,"3":false}
 *@param {Number/Object} fs采样频率
 *	若为数字，所有通道用同一采样频率
 *	若为对象，可分别指定不同通道的采集频率 如{"1":1000,"2":10000,"3":20000}
 */
function createCacheData(fs,cacheTimeLen=1,channelNum=8,isMultiData=false){
	let cache=[];
	//初始化通道频率、数据形式
	let fsObj=[],multiData=[];
	let isNum=varTypeof(fs)=='number';
	let isNum2=varTypeof(isMultiData)=='boolean';
	for(let i=1;i<=channelNum;i++){
		fsObj[i]=isNum?fs:fs[i];
		multiData[i]=isNum2?isMultiData:isMultiData[i];
	}	
	//初始化通道数据
	for(let i=1;i<=channelNum;i++){
		cache[i]={
			//通道索引
			channel:i,
			//采集频率
			fs:fsObj[i],
			//是否为多组数据
			isMultiData:multiData[i],
			//最大缓存点数  采集频率*缓存时间
			maxLen:fsObj[i]*cacheTimeLen,
			//缓存数据
			value:[],
			//数据对应横坐标
			xAxis:[],
			//数据对应横坐标
			insert(data,xAxis){
				insert(this.channel,data,xAxis);
			},
			//获取数据 start end 分别为开始与结束位置的百分比
			getData(start,end){
				return getData(this.channel,start,end)
			},
			//清空数据
			clear(){
				cache[this.channel].value=[];
				cache[this.channel].xAxis=[];
				cache[this.channel].newData=false;
			},
			//获取精简数据 start end 分别为开始与结束位置的百分比 len为返回的数据长度
			extract(start,end,len=2000){
				let data=getData(this.channel,start,end);
				if(this.isMultiData){
					return intervalExtractFunc(data.xAxis,data.value,len);
				}else{				
					return extractFunc(data.xAxis,data.value,len);
				}
			}
		}
	}
	//清空所有通道缓存数据
	function clear(){
		cache.forEach(v=>{
			v.value=new Array(maxLen).fill("");
			v.xAxis=new Array(maxLen).fill("");
		})
	}
	/**
	 * 添加数据
	 * @param {Number} channel 数据所属通道
	 * @param {Array} data 通道数据
	 * @param {Array} xAxis 数据对应横坐标
	 * @param {boolean} isMultiData 数据是否为多组数据
	 */
	function insert(channel,data,xAxis){
		let channelData=cache[channel];
		if(!channelData.isMultiData){
			//单组数据时
			let len=data.length;
			if(channelData.value.length==0){
				channelData.value=new Array(channelData.maxLen).fill("");
				channelData.xAxis=new Array(channelData.maxLen).fill("");
			}
			for(let i=0;i<len;i++){
				channelData.value.push(data[i]);
				channelData.xAxis.push(xAxis[i]);
			}
			//数据量超过最大长度时
			if(channelData.value.length>channelData.maxLen){
				channelData.value.splice(0,data.length);
				channelData.xAxis.splice(0,data.length);
			}
		}else{
			//多组数据时
			let len=data[0].length;
			let len2=data.length;
			for(let i=0;i<len;i++){
				for(let k=0;k<len2;k++){
					//若该组数据不是数组类型，则表示未初始化
					if(varTypeof(channelData.value[k])!='array'){
						channelData.value[k]=new Array(channelData.maxLen).fill("")
					}
					channelData.value[k].push(data[k][i]);
				}
				channelData.xAxis.push(xAxis[i]);
			}
			if(channelData.value[0].length>channelData.maxLen){
				for(let k=0;k<len2;k++){
					channelData.value[k].splice(0,data[k].length);
				}
				channelData.xAxis.splice(0,xAxis.length);
			}
		}		
		channelData.newData=true;
	}
	
	/**
	 * 获取片段数据
	 * @param {Number} start 开始位置百分比
	 * @param {Number} end 结束位置百分比
	 * @return {Object} 通道数据
	 */
	function getData(channel,start=0,end=1){
		let channelData=cache[channel],value;
		start*=channelData.maxLen;
		end*=channelData.maxLen;
		if(channelData.isMultiData){
			//多组数据时
			value=[];
			channelData.value.forEach(v=>{
				value.push(v.slice(start,end));
			})
		}else{
			//单组数据时
			value=channelData.value.slice(start,end);
		}
		return {
			value,
			xAxis:channelData.xAxis.slice(start,end)
		}
	}
	
	return {
		clear,
		cache
	}
}

//获取变量类型
function varTypeof(data){
	let type=Object.prototype.toString.call(data);
	return type.replaceAll(/(\[object )|(\])/g,"").toLowerCase();
}


/** 
 * 按最大最小值来取精简数据
 * @param {Array} x 横坐标数据
 * @param {Array} y 纵数据 
 * @return {Object} 精简后的数据
 */
function extractFunc(x,y,resLen=2000){	
	if(resLen>=y.length){
		let interval=parseInt(y.length/5);
		return {x,y,interval}
	}
	let interval=parseInt(resLen/5);
	resLen=parseInt(resLen/2);
	let len=y.length;
	let splitNum=parseInt(len/resLen);
	let res={x:[],y:[],interval,min:null,max:null}
	//console.log('splitNum',splitNum,len/resLen);
	let k2,z,minArr=[],maxArr=[];
	let min,max,minIndex,maxIndex,tmpdata;
	for(let i=0;i<len;i+=splitNum){
		//let t=Date.now(),t2;
		tmpdata=y.slice(i,i+splitNum);
		//t2=Date.now()-t;if(t2>50)console.log('slice',t2);
		
		//t=Date.now();
		min=Math.min(...tmpdata);
		max=Math.max(...tmpdata);
		//t2=Date.now()-t;if(t2>50)console.log('最大最小',t2);
		
		//t=Date.now();
		minIndex=tmpdata.indexOf(min)+i;
		maxIndex=tmpdata.indexOf(max)+i;		
		//t2=Date.now()-t;if(t2>50)console.log('最大最小位置',t2);
		minArr.push(min)
		maxArr.push(max)
		if(minIndex>maxIndex){
			res.x.push(x[maxIndex],x[minIndex]);
			res.y.push(max,min);
		}else{
			res.x.push(x[minIndex],x[maxIndex]);
			res.y.push(min,max);
		}
	}
	res.min=Math.min(...minArr);
	res.max=Math.max(...maxArr);
	return res;
}

/** 
 * 按间隔数来取精简数据,用于单个通道有多组数据展示时，展示效果上不如按最大最小值精简
 * @param {Array} x 横坐标数据
 * @param {Array[Array]} y 多组数据 如[[1,2,3],[1,2,3],...]
 * @return {Object} 精简后的数据
 */
function intervalExtractFunc(x,y,resLen=3000){
	if(resLen>=y[0].length){
		let interval=parseInt(y[0].length/5);
		return {x,y,interval,min:null,max:null}
	}
	let interval=parseInt(resLen/5);
	let len=y[0].length;
	let len2=y.length;
	let splitNum=parseInt(len/resLen);
	let y2=[];
	y.forEach(v=>y2.push([]));
	let res={x:[],y:y2,interval,min:null,max:null};
	for(let i=0;i<len;i+=splitNum){
		res.x.push(x[i]);
		for(let k=0;k<len2;k++){
			res.y[k].push(y[k][i]);
		}
	}
	return res;
}
